function SecureTxItem() {
    /**
     * state 状态值
     *
     * 'init' 初始状态
     * 'underway' 进行中
     * 'refund' 退款中
     * 'to.negotiate' 收款方发起协商中
     * 'from.negotiate' 付款方发起协商中
     * 'finish'
     */
    this.state = '';

    // 交易hash
    this.hash = '';

    this.from = ''; // 付款者
    this.to = ''; // 收款者

    this.txBalance = new BigNumber(0); // 合约账户交易余额
    this.marginBalance = new BigNumber(0); // 合约账户保证金余额

    this.txAmount = new BigNumber(0); // 交易金数额
    this.marginAmount = new BigNumber(0); // 最低纠纷保证金额度

    this.txDuration = new BigNumber(0); // 交易周期
    this.disputeDuration = new BigNumber(0); // 纠纷周期

    this.txStart = new BigNumber(0); // 交易开始时间
    this.disputeStart = new BigNumber(0); // 纠纷开始时间

    this.createdAt = new BigNumber(0); // 交易创建时间
    this.updatedAt = new BigNumber(0); // 交易创建时间
    this.closedAt = new BigNumber(0); // 交易完成时间
}
SecureTxItem.prototype = {
    toString: function() {
        return JSON.stringify(this);
    }
};

var SecureTransaction = function() {
    // 交易记录
    LocalContractStorage.defineMapProperty(this, 'tx');
    LocalContractStorage.defineProperty(this, 'txSize');
    LocalContractStorage.defineMapProperty(this, 'txIndex');

    // 用户交易记录
    LocalContractStorage.defineMapProperty(this, 'userTxSize');
    LocalContractStorage.defineMapProperty(this, 'userTxIndex');

    // 账单
    LocalContractStorage.defineMapProperty(this, 'transferSize');
    LocalContractStorage.defineMapProperty(this, 'transferIndex');

    // 事件
    LocalContractStorage.defineMapProperty(this, 'eventSize');
    LocalContractStorage.defineMapProperty(this, 'eventIndex');
};

SecureTransaction.prototype = {
    init: function() {
        this.txSize = 0;
    },
    // 查询转账记录
    _getTransfers: function(hash) {
        var size = this.transferSize.get(hash);
        var items = [];

        for (var i = size - 1; i >= 0; i--) {
            var transfer = this.transferIndex.get(hash + '.' + i);
            items.push(transfer);
        }
        return items;
    },
    // 记录转账
    _recordTransfer: function(hash, transfer) {
        var transferSize = this.transferSize.get(hash) * 1;
        this.transferIndex.set(hash + '.' + transferSize, transfer);
        this.transferSize.set(hash, transferSize + 1);
    },
    // 查询操作记录
    _getEvents: function(hash) {
        var size = this.eventSize.get(hash);
        var items = [];

        for (var i = size - 1; i >= 0; i--) {
            var transfer = this.eventIndex.get(hash + '.' + i);
            items.push(transfer);
        }
        return items;
    },
    // 记录操作
    _recordEvent: function(hash, event) {
        var eventSize = this.eventSize.get(hash) * 1;
        this.eventIndex.set(hash + '.' + eventSize, event);
        this.eventSize.set(hash, eventSize + 1);
    },
    // 查询交易列表
    getAllTx: function(offset, limit) {
        offset = parseInt(offset);
        limit = parseInt(limit);

        var items = [];
        if (offset > this.txSize) {
            return {
                code: 10001,
                data: items,
                size: this.txSize
            };
        }

        var num = offset + limit;
        if (num > this.txSize) {
            num = this.txSize;
        }

        for (var i = num - 1; i >= offset; i--) {
            var hash = this.txIndex.get(i);
            var secureTxItem = this.tx.get(hash);
            items.push(secureTxItem);
        }
        return {
            code: 10002,
            data: items,
            size: this.txSize
        };
    },
    // 查询用户交易列表
    getUserTx: function(wallet, offset, limit) {
        offset = parseInt(offset);
        limit = parseInt(limit);

        if (!Blockchain.verifyAddress(wallet)) {
            return {code: 20001};
        }

        var size = this.userTxSize.get(wallet);
        var items = [];

        if (offset > size) {
            return {
                code: 10001,
                data: items,
                size: size
            };
        }

        var num = offset + limit;
        if (num > size) {
            num = size;
        }

        for (var i = num - 1; i >= offset; i--) {
            var hash = this.userTxIndex.get(wallet + '.' + i);
            var secureTxItem = this.tx.get(hash);
            items.push(secureTxItem);
        }
        return {
            code: 10002,
            data: items,
            size: this.txSize
        };
    },

    // 查询交易详情
    getTx: function(hash) {
        var detail = this.tx.get(hash);
        if (!detail) {
            return {code: 20001};
        }

        return {
            code: 10001,
            data: {
                detail: detail,
                transfers: this._getTransfers(hash),
                events: this._getEvents(hash)
            }
        };
    },
    _getTx: function(hash) {
        return this.tx.get(hash);
    },

    // 付款方发起交易
    fromCreate: function(to, txDuration, marginAmount, disputeDuration) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            value = Blockchain.transaction.value,
            hash = Blockchain.transaction.hash,
            contract = Blockchain.transaction.to;

        txDuration = new BigNumber(txDuration); // 交易周期
        disputeDuration = new BigNumber(disputeDuration); // 纠纷周期
        marginAmount = new BigNumber(marginAmount); // 最低纠纷保证金额度

        // 检查数据完整性
        if (!Blockchain.verifyAddress(to)) {
            to = 'inValid';
        }
        if (txDuration.isNaN() || !txDuration.isInteger() || txDuration.lt(1)) {
            txDuration = new BigNumber(7);
        }

        if (marginAmount.isNaN() || marginAmount.lte(1000000000000)) {
            marginAmount = new BigNumber(1000000000000);
        }

        if (disputeDuration.isNaN() || !disputeDuration.isInteger() || disputeDuration.lt(1)) {
            disputeDuration = new BigNumber(3);
        }
        // if (!payFee.eq(amount.multipliedBy(0.2))) {
        //     throw new Error('10004');
        // }

        // 创建新交易
        var secureTxItem = new SecureTxItem();
        secureTxItem.state = 'init'; // 交易状态
        secureTxItem.hash = hash; // 交易hash
        secureTxItem.from = from; // 付款者
        secureTxItem.to = to; // 收款者
        secureTxItem.txBalance = value; // 合约账户交易余额
        secureTxItem.marginBalance = new BigNumber(0); // 合约账户保证金余额
        secureTxItem.txAmount = value; // 交易金数额
        secureTxItem.marginAmount = marginAmount; // 最低纠纷保证金额度
        secureTxItem.txDuration = txDuration; // 交易周期
        secureTxItem.disputeDuration = disputeDuration; // 纠纷周期
        secureTxItem.createdAt = timestamp; // 交易创建时间
        secureTxItem.updatedAt = timestamp; // 交易创建时间

        // 交易上链
        this.tx.put(hash, secureTxItem);

        // 交易索引
        this.txIndex.set(this.txSize, hash);
        this.txSize += 1;

        // 用户交易索引
        var fromTxSize = this.userTxSize.get(from) * 1;
        this.userTxIndex.set(from + '.' + fromTxSize, hash);
        this.userTxSize.set(from, fromTxSize + 1);

        var toTxSize = this.userTxSize.get(to) * 1;
        this.userTxIndex.set(to + '.' + toTxSize, hash);
        this.userTxSize.set(to, toTxSize + 1);

        // 日志记录
        this._recordTransfer(hash, {
            from: from,
            to: contract,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(hash, {
            operator: from,
            content: 'fromCreate',
            timestamp: timestamp
        });
    },
    // 付款方取消交易
    fromCancel: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to;

        var secureTxItem = this._getTx(hash);
        // 交易必须在 init 状态才可以取消交易
        if (secureTxItem.state !== 'init') {
            throw new Error('{"msg": "state must be init.", "code": 20001}');
        }
        // 只有付款方可以取消交易
        if (from !== secureTxItem.from) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.from + ' .", "code": 20002}');
        }

        // 取消交易,将账款从合约账户转出到付款方
        var value = secureTxItem.txBalance;
        var res = Blockchain.transfer(from, value);
        if (!res) {
            throw new Error('{"msg": "transfer failed.", "code": 20003}');
        }

        // 更新合约
        secureTxItem.txBalance = new BigNumber(0);
        secureTxItem.updatedAt = timestamp;
        secureTxItem.closedAt = timestamp;
        secureTxItem.state = 'finish';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: contract,
            to: from,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'fromCancel',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 付款方确认付款
    fromComfirm: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to;

        var secureTxItem = this._getTx(hash);
        // 交易必须在 underway 状态才可以确认付款
        if (secureTxItem.state !== 'underway') {
            throw new Error('{"msg": "state must be underway.", "code": 20001}');
        }
        // 只有付款方可以确认付款
        if (from !== secureTxItem.from) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.from + ' .", "code": 20002}');
        }

        // 确认付款,将账款从合约账户转出到收款方
        var value = secureTxItem.txBalance;
        var res = Blockchain.transfer(secureTxItem.to, value);
        if (!res) {
            throw new Error('{"msg": "transfer failed.", "code": 20003}');
        }

        // 更新合约
        secureTxItem.txBalance = new BigNumber(0);
        secureTxItem.updatedAt = timestamp;
        secureTxItem.closedAt = timestamp;
        secureTxItem.state = 'finish';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: contract,
            to: secureTxItem.to,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'fromComfirm',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 付款方申请退款
    fromRefund: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from;

        var secureTxItem = this._getTx(hash);
        // 交易必须在 underway 状态才可以申请退款
        if (secureTxItem.state !== 'underway') {
            throw new Error('{"msg": "state must be underway.", "code": 20001}');
        }
        // 交易必须在 有效周期 内才可以申请退款
        var txDuration = new BigNumber(secureTxItem.txDuration);
        var txDeadline = txDuration.times(86400).plus(secureTxItem.txStart);
        if (txDeadline.lte(timestamp)) {
            throw new Error('{"msg": "The transaction has expired.", "code": 20002}');
        }

        // 只有付款方可以申请退款
        if (from !== secureTxItem.from) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.from + ' .", "code": 20003}');
        }

        // 更新合约
        secureTxItem.disputeStart = timestamp;
        secureTxItem.updatedAt = timestamp;
        secureTxItem.state = 'refund';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'fromRefund',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 付款方申请协商
    fromDoNegotiate: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to,
            value = Blockchain.transaction.value;

        var secureTxItem = this._getTx(hash);

        // 必须缴纳足额保证金才可申请协商
        if (value.lt(secureTxItem.marginAmount)) {
            throw new Error('{"msg": "Margin Amount should be greater than ' + secureTxItem.marginAmount + '.", "code": 20001}');
        }

        // 交易必须在 to.negotiate 状态才可以申请协商
        if (secureTxItem.state !== 'to.negotiate') {
            throw new Error('{"msg": "state must be to.negotiate.", "code": 20002}');
        }

        // 交易必须在 纠纷有效期 内才可以申请协商
        var disputeDuration = new BigNumber(secureTxItem.disputeDuration);
        var disputeDeadline = disputeDuration.times(86400).plus(secureTxItem.disputeStart);
        if (disputeDeadline.lte(timestamp)) {
            throw new Error('{"msg": "The Dispute has expired.", "code": 20003}');
        }

        // 只有付款方可以申请协商
        if (from !== secureTxItem.from) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.from + ' .", "code": 20004}');
        }

        // 更新合约
        var marginBalance = new BigNumber(secureTxItem.marginBalance);
        secureTxItem.marginBalance = marginBalance.plus(value);
        secureTxItem.disputeStart = timestamp;
        secureTxItem.updatedAt = timestamp;
        secureTxItem.state = 'from.negotiate';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: from,
            to: contract,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'fromDoNegotiate',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 付款方接受协商
    fromAcceptNegotiate: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to;

        var secureTxItem = this._getTx(hash);

        // 交易必须在 to.negotiate 状态才可以接受协商
        if (secureTxItem.state !== 'to.negotiate') {
            throw new Error('{"msg": "state must be to.negotiate.", "code": 20002}');
        }

        // 只有付款方可以接受协商
        if (from !== secureTxItem.from) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.from + ' .", "code": 20002}');
        }

        // 接受协商,将账款和保证金从合约账户转出到收款方
        var txBalance = new BigNumber(secureTxItem.txBalance);
        var value = txBalance.plus(secureTxItem.marginBalance);
        var res = Blockchain.transfer(secureTxItem.to, value);
        if (!res) {
            throw new Error('{"msg": "The transfer failed.", "code": 20003}');
        }

        // 更新合约
        secureTxItem.txBalance = new BigNumber(0);
        secureTxItem.marginBalance = new BigNumber(0);
        secureTxItem.updatedAt = timestamp;
        secureTxItem.closedAt = timestamp;
        secureTxItem.state = 'finish';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: contract,
            to: secureTxItem.to,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'fromAcceptNegotiate',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 付款方收取协商超时退款
    fromReceiveNegotiate: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to;

        var secureTxItem = this._getTx(hash);

        // 交易必须在 refund 和 from.negotiate 状态才可以收取超时退款
        if (secureTxItem.state !== 'refund' && secureTxItem.state !== 'from.negotiate') {
            throw new Error('{"msg": "state must be to.negotiate or refund.", "code": 20001}');
        }

        // 交易必须超过 纠纷有效期 才可以操作
        var disputeDuration = new BigNumber(secureTxItem.disputeDuration);
        var disputeDeadline = disputeDuration.times(86400).plus(secureTxItem.disputeStart);
        if (disputeDeadline.gt(timestamp)) {
            throw new Error('{"msg": "The dispute period is not expired.", "code": 20002}');
        }

        // 只有付款方可以接受协商
        if (from !== secureTxItem.from) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.from + ' .", "code": 20003}');
        }

        // 协商超时,将账款和保证金从合约账户转出到付款方
        var txBalance = new BigNumber(secureTxItem.txBalance);
        var value = txBalance.plus(secureTxItem.marginBalance);
        var res = Blockchain.transfer(secureTxItem.from, value);
        if (!res) {
            throw new Error('{"msg": "The transfer failed.", "code": 20004}');
        }

        // 更新合约
        secureTxItem.txBalance = new BigNumber(0);
        secureTxItem.marginBalance = new BigNumber(0);
        secureTxItem.updatedAt = timestamp;
        secureTxItem.closedAt = timestamp;
        secureTxItem.state = 'finish';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: contract,
            to: secureTxItem.from,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'fromReceiveNegotiate',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },

    // 收款方确认交易
    toComfirm: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from;

        var secureTxItem = this._getTx(hash);
        // 交易必须在 init 状态才可以确认交易
        if (secureTxItem.state !== 'init') {
            throw new Error('{"msg": "state must be init.", "code": 20001}');
        }
        // 只有收款方可以确认交易
        if (from !== secureTxItem.to) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.to + ' .", "code": 20002}');
        }

        // 更新合约
        secureTxItem.txStart = timestamp;
        secureTxItem.updatedAt = timestamp;
        secureTxItem.state = 'underway';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'toComfirm',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 收款方收取交易超时账款
    toReceive: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to;

        var secureTxItem = this._getTx(hash);

        // 交易必须在 underway 状态才可以操作
        if (secureTxItem.state !== 'underway') {
            throw new Error('{"msg": "state must be underway.", "code": 20001}');
        }
        // 交易必须超过 有效周期 才可以操作
        var txDuration = new BigNumber(secureTxItem.txDuration);
        var txDeadline = txDuration.times(86400).plus(secureTxItem.txStart);
        if (txDeadline.gt(timestamp)) {
            throw new Error('{"msg": "The transaction period is not expired.", "code": 20002}');
        }
        // 只有收款方可以确认付款
        if (from !== secureTxItem.to) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.to + ' .", "code": 20003}');
        }

        // 收款方收取交易超时,将账款从合约账户转出到收款方
        var value = secureTxItem.txBalance;
        var res = Blockchain.transfer(secureTxItem.to, value);
        if (!res) {
            throw new Error('{"msg": "The transfer failed.", "code": 20004}');
        }

        // 更新合约
        secureTxItem.txBalance = new BigNumber(0);
        secureTxItem.updatedAt = timestamp;
        secureTxItem.closedAt = timestamp;
        secureTxItem.state = 'finish';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: contract,
            to: secureTxItem.to,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'toReceive',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 收款方确认退款
    toRefundComfirm: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to;

        var secureTxItem = this._getTx(hash);

        // 交易必须在 refund 状态才可以确认退款
        if (secureTxItem.state !== 'refund') {
            throw new Error('{"msg": "state must be refund.", "code": 20001}');
        }
        // 只有收款方可以确认退款
        if (from !== secureTxItem.to) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.to + ' .", "code": 20002}');
        }

        // 确认退款,将账款从合约账户转出到付款方
        var value = secureTxItem.txBalance;
        var res = Blockchain.transfer(secureTxItem.from, value);
        if (!res) {
            throw new Error('{"msg": "The transfer failed.", "code": 20003}');
        }

        // 更新合约
        secureTxItem.txBalance = new BigNumber(0);
        secureTxItem.updatedAt = timestamp;
        secureTxItem.closedAt = timestamp;
        secureTxItem.state = 'finish';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: contract,
            to: secureTxItem.from,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'toRefundComfirm',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 收款方申请协商
    toDoNegotiate: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to,
            value = Blockchain.transaction.value;

        var secureTxItem = this._getTx(hash);

        // 必须缴纳足额保证金才可申请协商
        if (value.lt(secureTxItem.marginAmount)) {
            throw new Error('{"msg": "Margin Amount should be greater than ' + secureTxItem.marginAmount + '.", "code": 20001}');
        }

        // 交易必须在 refund 和 from.negotiate 状态才可以申请协商
        if (secureTxItem.state !== 'refund' && secureTxItem.state !== 'from.negotiate') {
            throw new Error('{"msg": "state must be refund or from.negotiate.", "code": 20002}');
        }

        // 交易必须在 纠纷有效期 内才可以申请协商
        var disputeDuration = new BigNumber(secureTxItem.disputeDuration);
        var disputeDeadline = disputeDuration.times(86400).plus(secureTxItem.disputeStart);
        if (disputeDeadline.lte(timestamp)) {
            throw new Error('{"msg": "The Dispute has expired.", "code": 20003}');
        }

        // 只有付款方可以申请协商
        if (from !== secureTxItem.to) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.to + ' .", "code": 20004}');
        }

        // 更新合约
        var marginBalance = new BigNumber(secureTxItem.marginBalance);
        secureTxItem.marginBalance = marginBalance.plus(value);
        secureTxItem.disputeStart = timestamp;
        secureTxItem.updatedAt = timestamp;
        secureTxItem.state = 'to.negotiate';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: from,
            to: contract,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'toDoNegotiate',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 收款方接受协商
    toAcceptNegotiate: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to;

        var secureTxItem = this._getTx(hash);

        // 交易必须在 from.negotiate 状态才可以接受协商
        if (secureTxItem.state !== 'from.negotiate') {
            throw new Error('{"msg": "state must be from.negotiate.", "code": 20001}');
        }

        // 只有收款方可以接受协商
        if (from !== secureTxItem.to) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.to + ' .", "code": 20002}');
        }

        // 接受协商,将账款和保证金从合约账户转出到付款方
        var txBalance = new BigNumber(secureTxItem.txBalance);
        var value = txBalance.plus(secureTxItem.marginBalance);
        var res = Blockchain.transfer(secureTxItem.from, value);
        if (!res) {
            throw new Error('{"msg": "The transfer failed.", "code": 20003}');
        }

        // 更新合约
        secureTxItem.txBalance = new BigNumber(0);
        secureTxItem.marginBalance = new BigNumber(0);
        secureTxItem.updatedAt = timestamp;
        secureTxItem.closedAt = timestamp;
        secureTxItem.state = 'finish';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: contract,
            to: secureTxItem.from,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'toAcceptNegotiate',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    },
    // 收款方收取协商超时退款
    toReceiveNegotiate: function(hash) {
        var timestamp = Blockchain.transaction.timestamp,
            from = Blockchain.transaction.from,
            contract = Blockchain.transaction.to;

        var secureTxItem = this._getTx(hash);

        // 交易必须在 to.negotiate 状态才可以收取超时退款
        if (secureTxItem.state !== 'to.negotiate') {
            throw new Error('{"msg": "state must be to.negotiate.", "code": 20001}');
        }

        // 交易必须超过 纠纷有效期 才可以操作
        var disputeDuration = new BigNumber(secureTxItem.disputeDuration);
        var disputeDeadline = disputeDuration.times(86400).plus(secureTxItem.disputeStart);
        if (disputeDeadline.gt(timestamp)) {
            throw new Error('{"msg": "The dispute period is not expired.", "code": 20002}');
        }

        // 只有收款方可以接受协商
        if (from !== secureTxItem.to) {
            throw new Error('{"msg": "From Address must be ' + secureTxItem.to + ' .", "code": 20003}');
        }

        // 协商超时,将账款和保证金从合约账户转出到收款方
        var txBalance = new BigNumber(secureTxItem.txBalance);
        var value = txBalance.plus(secureTxItem.marginBalance);
        var res = Blockchain.transfer(secureTxItem.to, value);
        if (!res) {
            throw new Error('{"msg": "The transfer failed.", "code": 20004}');
        }

        // 更新合约
        secureTxItem.txBalance = new BigNumber(0);
        secureTxItem.marginBalance = new BigNumber(0);
        secureTxItem.updatedAt = timestamp;
        secureTxItem.closedAt = timestamp;
        secureTxItem.state = 'finish';
        this.tx.set(secureTxItem.hash, secureTxItem);

        // 日志记录
        this._recordTransfer(secureTxItem.hash, {
            from: contract,
            to: secureTxItem.to,
            value: value,
            timestamp: timestamp
        });
        this._recordEvent(secureTxItem.hash, {
            operator: from,
            content: 'toReceiveNegotiate',
            timestamp: timestamp
        });

        return {
            code: 10001,
            data: secureTxItem
        };
    }
};
module.exports = SecureTransaction;
